home *** CD-ROM | disk | FTP | other *** search
- /* TALK: (c) Kees Lemmens; April 1993.
-
- Behaviour is copied from the (BSD) UNIX talk program, but the
- code is completely by myself.
-
- Program for ATARI ST (running under MINT) to make it possible
- to talk with any other person logged in.
- Relies on the utmp structure as defined in the stlogin.lzh
- package (also by me).
- If you don't have this, then you can only use the "-l tty"
- option. Talk then assumes that the username is root, unless
- the variable LOGNAME is set.
-
- It also needs a termcap file for screen handling on non-ST
- terminals. If you don't have termcap, talk uses vt52 (ST).
-
- Any questions or suggestions about this program can be send to:
- lemmens@dv.twi.tudelft.nl
- */
-
- /* standard headers */
-
- #include <stdio.h>
- #include <stdlib.h> /* getenv, malloc, free and exit */
- #include <string.h>
- #include <time.h>
-
- #include <osbind.h>
-
- /* UNIX headers */
-
- #include <utmp.h>
- #include <pwd.h>
- #include <termcap.h>
- #include <signal.h> /* especially for suspend routine */
- #include <sys\file.h> /* access */
- #include <sgtty.h> /* ioctl & tty structs */
-
- /* special headers */
- #include "ux_misc.h" /* mk_devnm + MINT functions */
-
- #define MASTER 0
- #define SLAVE 1
- #define UpWindow 0
- #define DownWindow 1
- #define Keyboard 1
-
- typedef struct { int line, col; } WindowPos;
-
- static char *_tcpent,*_tcpbuf;
- static char *CL,*CM,*SO,*SE,*CE;
- static int LINES,COLS;
- static WindowPos Up = {1, 0};
- static WindowPos Down = {0, 0};
-
- struct ltchars ltold,ltnew; /* disable suspend */
-
- void ttraw(struct ltchars *ltold,struct ltchars *ltnew)
- {
- if(ioctl(0, TIOCGLTC, (char *) ltold) < 0)
- puts("Can't do ioctl");
- ioctl(0, TIOCGLTC, (char *)ltnew);
-
- ltnew->t_suspc = ltnew->t_dsuspc = 0xFF;
- ioctl(0, TIOCSLTC, (char *) ltnew);
- }
-
- void ttcooked(struct ltchars *ltold)
- {
- ioctl(0, TIOCSLTC, (char *) ltold);
- }
-
- void InitTermcap(void)
- { char *tmp;
-
- if((tmp=getenv("TERM")) != NULL) /* use UNIX termcap */
- { _tcpent = (char *)malloc(2048); /* must be enough ! */
- tgetent(_tcpent,tmp);
- _tcpbuf = _tcpent +1024;
-
- CL = tgetstr("cl", &_tcpbuf); CM = tgetstr("cm", &_tcpbuf);
- SO = tgetstr("so", &_tcpbuf); SE = tgetstr("se", &_tcpbuf);
- CE = tgetstr("ce", &_tcpbuf);
- LINES = tgetnum("li"); COLS = tgetnum("co");
- }
- else /* set acceptable defaults : VT52 code */
- { CL = "\33H\33J"; CM = "\33Y%+ %+ ";
- SO = "\33p"; SE = "\33q";
- CE = "\33K";
- LINES = 24; COLS = 80;
- }
- }
-
- int outc(int c)
- { return putchar(c);
- }
-
- void clrscr(void)
- { tputs(CL,1,outc);
- }
-
- void gotoxy(int x,int y)
- { tputs(tgoto(CM, x, y),1,outc);
- }
-
- void EndTermcap(void)
- { free(_tcpent);
- }
-
- void usage(void)
- { fputs("\nUsage: talk [-l <line>] | [<username>]",stderr);
- exit(1);
- }
-
- void MsgPrint(char *string,int mode)
- { static int upline=0;
-
- upline++;
- if(mode || upline >= LINES/2)
- upline = 0;
-
- gotoxy(0,upline);
-
- tputs(CE,1,outc);
- puts(string);
- }
-
- void InitScreen(void)
- { int x;
-
- clrscr();
- gotoxy(0,LINES/2);
- for(x=0;x<COLS;x++)
- fputc('-',stdout);
- }
-
- int name2tty(char *name,char *totty)
- { extern int utmp_fd;
- int fl=1;
- struct utmp *w;
-
- setutent();
-
- while((w=getutent()) != NULL)
- { if(!strncmp(w->ut_name,name,sizeof(w->ut_name)) &&
- w->ut_type == USER_PROCESS)
- { if((fl=Pkill(w->ut_pid,SIGNULL)) != 0)
- { /* process does not exist */
- w->ut_type=DEAD_PROCESS;
- setutent(); /* rewind and */
- pututline(w); /* correct UTMP entry */
- }
- else break;
- }
- }
- endutent();
- if(fl) return -1;
-
- strncpy(totty,w->ut_line,sizeof(w->ut_line));
- return 0;
- }
-
- char *MakeChanName(char *name)
- { static char pipenam[40];
-
- strcpy(pipenam,"U:\\PIPE\\");
- strncat(pipenam,name,8);
- strcat(pipenam,".tlk");
-
- return pipenam;
- }
-
- int MakeChan(char *name, int mode)
- { char *channel;
- int fp;
- int mask = (mode == MASTER ? O_CREAT : 0);
-
- channel = MakeChanName(name);
- if((fp=open(channel,O_RDWR|mask)) < 0)
- { puts("Can't open pipe !");
- exit(1);
- }
- return fp;
- }
-
- char *BuildttyName(int lfl,char *name)
- { static char fulltty[100];
- char totty[20];
-
- if(lfl)
- strncpy(totty,name,19);
- else
- { if(name2tty(name,totty) < 0)
- { puts("[Your party is not logged on]");
- exit(0);
- }
- }
- mk_devnm(fulltty,totty);
- return fulltty;
- }
-
- int WaitforConnect(int channel)
- { char tmp=0;
-
- write(channel,&tmp,1L);
-
- if(Finstat(Keyboard))
- { read(1,&tmp,1);
- if(tmp=='\003' || tmp=='\004')
- return -1;
- }
- if(Finstat(channel) == 0)
- { sleep(1);
- return 0;
- }
- else
- { while(Finstat(channel))
- read(channel,&tmp,1); /* flush channel */
-
- InitScreen();
- MsgPrint( "[Connection established; quit=Ctrl-D;"
- " clrscr=Ctrl-L]",1);
- return 1;
- }
- }
-
- void SuspendTalk(void)
- { long omask;
-
- if (getenv("SHLVL") != NULL) /* there is a running (C) shell */
- { omask= sigsetmask(0);
- ttcooked(<old);
- (void) kill(0, SIGTSTP);
- (void) Psigsetmask(omask);
- ttraw(<old,<new);
- InitScreen();
- MsgPrint("[Connection resumed]",1);
- }
- else
- MsgPrint("[No shell active]",1);
- gotoxy(Up.col,Up.line); /* restore cursor */
- }
-
- void WindowSet(char c,WindowPos *pos,int window)
- { static int previouswindow;
- int offset=0;
-
- if (window == DownWindow)
- offset = LINES/2 + 1;
-
- if(pos->col >= COLS || c == '\015')
- { pos->col=0; pos->line++;
-
- if(pos->line >= LINES/2)
- pos->line=0;
- }
-
- /* set or restore cursor position */
- if (window != previouswindow || pos->col == 0)
- gotoxy(pos->col,pos->line + offset);
-
- if(pos->col == 0) /* clear line */
- tputs(CE,1,outc);
-
- if (c == '\015') /* simulate newline (looks better) */
- gotoxy(pos->col,pos->line + offset);
- else
- putchar(c);
-
- pos->col++;
- previouswindow = window;
- }
-
- void StartTalk(int channel)
- { char toggle=0, TalkChar=0;
-
- /*
- 1: Ctrl-C interrupt doesn't give a stop signal to the other
- side, so it must be captured to avoid problems.
-
- 2: The toggle is used to give every side an equal chance.
- This makes it impossible that a constant stream from one
- side prevents the other the possibility to log off !
- */
- signal(SIGINT,SIG_IGN);
-
- while(TalkChar!='\004')
- { if(toggle)
- { if(Finstat(channel)) /* other side */
- {
- read(channel,&TalkChar,1);
- WindowSet(TalkChar,&Down,DownWindow);
- }
- }
- else
- { if(Finstat(Keyboard)) /* own side */
- {
- /* don't echo: unfortunately sgttyb doesn't work */
- TalkChar=Cnecin();
- WindowSet(TalkChar,&Up,UpWindow);
-
- if(TalkChar == '\014') /* Ctrl-L: clear screen */
- { InitScreen();
- Up.line = Up.col = Down.col = Down.line = 0;
- continue;
- }
- /* Ctrl-Z : jump to shell */
-
- if(TalkChar == '\032')
- { SuspendTalk();
- continue;
- }
- write(channel,&TalkChar,1);
- }
- }
- toggle ^= 1;
- }
- }
-
- int SendInvitation(char *totty,char *name,int channel,int repeat)
- { int st,x,fp;
- time_t sec;
- char *ttyname,message[250];
- char *format=
- "\07\r\nMessage from TalkDaemon@Atari.Ste at %.8s "
- "...\r\ntalkd: Connection requested by %s (%s)"
- " \r\ntalkd: Please respond with: talk %s\r\n";
-
- if((ttyname = getenv("TTYNAME")) == NULL)
- ttyname = "console";
-
- signal(SIGTTOU,SIG_IGN);
-
- if((fp=open(totty,O_WRONLY)) < 0)
- { fputs("Can't open tty",stderr);
- exit(1);
- }
-
- time(&sec);
- sprintf(message,format,ctime(&sec)+11,name,ttyname,name);
-
- InitScreen();
- MsgPrint("[Waiting for your party to respond]",1);
-
- x=0;
- do
- { if(x++ == 0)
- write(fp,message,strlen(message));
- if(x >= repeat)
- { MsgPrint("[Ringing your party again]",0);
- x=0;
- }
- }while((st=WaitforConnect(channel)) == 0);
-
- close(fp);
- return st;
- }
-
- int CheckStatus(char *pipename)
- {
- if(access(MakeChanName(pipename),0) < 0)
- return MASTER;
- else
- return SLAVE;
- }
-
- void main(int argc,char *argv[])
- { char *totty,*pipename;
- int channel; /* communication pipe */
- int lfl = 0, ring = 20;
-
- if(argc<2) usage();
-
- while(--argc>0) /* parse options */
- { if(*argv[1]=='-')
- { switch(*(++argv[1]))
- { case 'l': lfl=1;
- break;
- default : usage();
- }
- ++argv;
- }
- }
- InitTermcap();
- ttraw(<old,<new); /* disable Ctrl-Z */
-
- switch(CheckStatus(argv[1]))
- { case MASTER :
- totty=BuildttyName(lfl,argv[1]);
- if((pipename = getenv("LOGNAME")) == NULL)
- pipename = "root";
-
- channel= MakeChan(pipename,MASTER);
- if(SendInvitation(totty,pipename,channel,ring) <0)
- break;
- StartTalk(channel);
- break;
- case SLAVE :
- pipename=argv[1];
-
- channel= MakeChan(pipename,SLAVE);
- while(WaitforConnect(channel)==0);
- StartTalk(channel);
- break;
- }
- clrscr();
- MsgPrint("[Connection closing. Exiting]",1);
- EndTermcap();
-
- ttcooked(<old);
- exit(0);
- }